/**
 * @(#)ApkLoginTypeServiceImpl.java 2016年11月14日
 * Copyright(C) 2016 ZHEXIN IT CO.,LTD. All rights reserved.
 */
package org.jsbd.boss.service.impl;

import org.jsbd.boss.common.redis.RedisClient;
import org.jsbd.boss.dao.IApkLoginTypeDAO;
import org.jsbd.boss.domian.channel.ApkLoginTypeConfig;
import org.jsbd.boss.enums.LoginTypeEnum;
import org.jsbd.boss.service.IApkLoginTypeService;
import org.jsbd.boss.util.CacheKey;
import org.jsbd.boss.util.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.connection.ReturnType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 获取ap登录方式配置
 * 
 * @author <a href="mailto:xupengcheng@zhexinit.com" >徐鹏程</a>
 * @version 1.0.0
 */
@Service
public class ApkLoginTypeServiceImpl implements IApkLoginTypeService {
	public static final Logger LOGGER = LoggerFactory.getLogger(ApkLoginTypeServiceImpl.class);
	@Resource
	private IApkLoginTypeDAO apkLoginTypeDAO;

	@Resource
	private RedisClient redisClient;

	private String getLeftLoginNumLua() {
		StringBuilder sb = new StringBuilder();
		sb.append("local result={} local j=1");
		// 如果没设置这个值的话默认设置为0，这个值是在定时器更新的
		sb.append(" for i = 1,#KEYS,3 do redis.call('hincrby', KEYS[i], KEYS[i+1],0) redis.call('hincrby', KEYS[i], KEYS[i+2],0)");
		sb.append(" result[j]= redis.call('hget', KEYS[i], KEYS[i+1])-redis.call('hget', KEYS[i], KEYS[i+2]) j=j+1 end return result");
		return sb.toString();
	}

	/**
	 * 
	 * getLeftLoginTypeNum:登录方式剩余
	 * 
	 * @author <a href="mailto:xupengcheng@zhexinit.com" >徐鹏程</a>
	 * @param apks
	 * @return
	 */
	@Override
	public List<Integer> getLeftLoginTypeNum(List<String> apks, Integer loginType) {
		List<Integer> result = new ArrayList<Integer>();
		if (apks != null && apks.size() > 0) {
			List<String> apkKeys = new ArrayList<String>();
			String loginTotalKey = loginType + "total";
			String loginExecKey = loginType + "exectotal";
			for (int i = 0; i < apks.size(); i++) {
				String loginKey = CacheKey.APK_LOGIN_KEY + DateUtil.getDaysOfTime() + apks.get(i);
				apkKeys.add(loginKey);
				apkKeys.add(loginTotalKey);
				apkKeys.add(loginExecKey);
			}
			Object retult = redisClient.eval(getLeftLoginNumLua(), ReturnType.MULTI, apkKeys.toArray(new String[0]));
			if (retult != null) {
				List<Long> numList = (List) retult;
				for (int i = 0; i < numList.size(); i++) {
					Long currNum = (Long) numList.get(i);
					int value = currNum == null ? 0 : currNum.intValue();
					result.add(value);
				}
			}
		}
		return result;
	}

	private boolean isExists(Integer loginType, List<ApkLoginTypeConfig> list) {
		for (ApkLoginTypeConfig login : list) {
			if (login.getLoginType().intValue() == loginType.intValue()) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 
	 * selectApkLoginConfig:根据登录类型获取apk
	 * 
	 * @author <a href="mailto:xupengcheng@zhexinit.com" >徐鹏程</a>
	 * @param loginType
	 * @return
	 */
	@Override
	public List<ApkLoginTypeConfig> selectApkLoginConfig(Integer loginType) {
		String key = CacheKey.APK_LOGIN_KEY + "LOGINTYPE" + loginType;
		Object obj = redisClient.get(key);
		if (obj != null) {
			return (List<ApkLoginTypeConfig>) obj;
		} else {
			if (redisClient.setNX(key + "_LOCK", 1, 10)) {
				ApkLoginTypeConfig config = new ApkLoginTypeConfig();
				config.setLoginType(loginType);
				List<ApkLoginTypeConfig> list = apkLoginTypeDAO.selectLoginTypeList(config);
				if (list == null) {
					list = new ArrayList<ApkLoginTypeConfig>();
				}
				redisClient.put(key, list, 300);
				return list;
			}
			return null;
		}
	}

	@Override
	public List<ApkLoginTypeConfig> selectApkLoginConfigNoCache(String mark) {
		ApkLoginTypeConfig config = new ApkLoginTypeConfig();
		config.setMark(mark);
		List<ApkLoginTypeConfig> targetList = new ArrayList<ApkLoginTypeConfig>();
		List<ApkLoginTypeConfig> list = apkLoginTypeDAO.selectApkLoginTypeConfig(config);
		targetList.addAll(list);
		for (Integer login : LoginTypeEnum.getMap().keySet().toArray(new Integer[0])) {
			if (list != null && list.size() > 0) {
				if (!isExists(login, list)) {
					ApkLoginTypeConfig loginConfig1 = new ApkLoginTypeConfig();
					loginConfig1.setLoginType(login);
					loginConfig1.setMark(mark);
					loginConfig1.setRate(0);
					targetList.add(loginConfig1);
				}
			} else {
				ApkLoginTypeConfig loginConfig1 = new ApkLoginTypeConfig();
				loginConfig1.setLoginType(login);
				loginConfig1.setMark(mark);
				loginConfig1.setRate(0);
				targetList.add(loginConfig1);
			}
		}

		return targetList;
	}

	@Override
	public void insertApkLoginTypeConfig(List<ApkLoginTypeConfig> apkConfigs) {
		apkLoginTypeDAO.insertApkLoginTypeConfig(apkConfigs);
	}

	@Override
	public void updateApkLoginConfig(List<ApkLoginTypeConfig> apkLoginTypeList) {
		apkLoginTypeDAO.insertApkLoginTypeConfig(apkLoginTypeList);
	}

	@Override
	public void insertAndUpdateApkLoginTypeConfig(List<ApkLoginTypeConfig> apkLoginTypeList) {
		apkLoginTypeDAO.insertAndUpdateApkLoginTypeConfig(apkLoginTypeList);
	}

	@Override
	public List<ApkLoginTypeConfig> selectApkLoginConfigNoCache() {
		List<ApkLoginTypeConfig> targetList = new ArrayList<ApkLoginTypeConfig>();
		for (Integer login : LoginTypeEnum.getMap().keySet().toArray(new Integer[0])) {
			ApkLoginTypeConfig loginConfig1 = new ApkLoginTypeConfig();
			loginConfig1.setLoginType(login);
			loginConfig1.setRate(0);
			targetList.add(loginConfig1);
		}
		return targetList;
	}

	@Override
	public void updateRateByMark(String mark) {
		apkLoginTypeDAO.updateRateByMark(mark);
	}

	@Override
	public List<ApkLoginTypeConfig> selectLoginBaseList (Integer loginType){
		String key = CacheKey.APK_LOGIN_KEY + "LOGIN_BASE" + loginType;
		Object obj = redisClient.get(key);
		if (obj != null) {
			return (List<ApkLoginTypeConfig>) obj;
		} else {
			if (redisClient.setNX(key + "_LOCK", 1, 10)) {
				ApkLoginTypeConfig config = new ApkLoginTypeConfig();
				config.setLoginType(loginType);
				List<ApkLoginTypeConfig> list = apkLoginTypeDAO.selectLoginBaseList(config);
				if (list == null) {
					list = new ArrayList<ApkLoginTypeConfig>();
				}
				redisClient.put(key, list, 300);
				return list;
			}
			return null;
		}
	}

	@Override
	@Transactional
	public void insertAndUpdateApkLoginTypeConfigNews(List<ApkLoginTypeConfig> loginConfigs, List<Integer> types, String mark) {
		apkLoginTypeDAO.insertAndUpdateApkLoginTypeConfig(loginConfigs);
		Map<String, Object> param = new HashMap<>();
		param.put("mark", mark);
		param.put("types", types);
		apkLoginTypeDAO.delteByMarkAndTypes(param);
	}

}
